home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 16 / Example 16.1 / GroupAI.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-30  |  6.1 KB  |  295 lines

  1. #include "groupAI.h"
  2. #include "masterAI.h"
  3. #include "strategyMap.h"
  4.  
  5. GROUPAI::GROUPAI(MASTERAI *_master)
  6. {
  7.     m_pMaster = _master;
  8.     m_task = TASK_NONE;
  9.     m_state = GROUP_STATE_IDLE;
  10. }
  11.  
  12. GROUPAI::~GROUPAI()
  13. {
  14.     //Reset group pointer for all group members
  15.     for(int i=0;i<m_members.size();i++)
  16.         m_members[i]->m_pGroup = NULL;
  17. }
  18.  
  19. void GROUPAI::AddMember(MAPOBJECT *newMember)
  20. {
  21.     if(Find(m_members, newMember) < 0)
  22.     {
  23.         newMember->m_pGroup = this;    
  24.         m_members.push_back(newMember);
  25.     }
  26. }
  27.  
  28. void GROUPAI::RemoveMember(MAPOBJECT *oldMember)
  29. {
  30.     int place = Find(m_members, oldMember);
  31.  
  32.     if(place >= 0)
  33.     {
  34.         oldMember->m_pGroup = NULL;
  35.         m_members.erase(&m_members[place]);
  36.     }
  37. }
  38.  
  39. void GROUPAI::DisbandGroup()
  40. {
  41.     while(!m_members.empty())
  42.     {
  43.         RemoveMember(m_members[0]);
  44.     }
  45.  
  46.     m_members.clear();
  47.     m_visibleEnemies.clear();
  48. }
  49.  
  50. void GROUPAI::EnemiesSpotted(std::vector<MAPOBJECT*> &manyEnemies)
  51. {
  52.     if(m_visibleEnemies.size() > 30)return;
  53.  
  54.     for(int i=0;i<manyEnemies.size();i++)
  55.         if(Find(m_visibleEnemies, manyEnemies[i]) < 0)
  56.             m_visibleEnemies.push_back(manyEnemies[i]);
  57. }
  58.  
  59. void GROUPAI::SetTask(int newTask, RECT *area)
  60. {
  61.     m_task = newTask;
  62.  
  63.     if(area == NULL)
  64.         m_task = TASK_NONE;
  65.     else m_mapArea = *area;
  66. }
  67.  
  68. GROUPAI* GROUPAI::SplitGroup(std::vector<int> units)
  69. {
  70.     if(units.empty() || m_members.empty())return NULL;
  71.  
  72.     GROUPAI *newGroup = new GROUPAI(m_pMaster);
  73.  
  74.     try
  75.     {
  76.         bool done = false;
  77.  
  78.         while(!done)
  79.         {
  80.             //Transfer member
  81.             for(int i=0;i<m_members.size();i++)
  82.                 if(!m_members[i]->m_isBuilding && m_members[i]->m_type == units[0])
  83.                 {    
  84.                     MAPOBJECT* unit = m_members[i];
  85.                     RemoveMember(unit);
  86.                     newGroup->AddMember(unit);
  87.                     break;
  88.                 }
  89.             
  90.             units.erase(units.begin());
  91.             done = units.empty() || m_members.empty();
  92.         }
  93.  
  94.         if(newGroup->isDead())
  95.         {
  96.             delete newGroup;
  97.             newGroup = NULL;
  98.         }
  99.     }
  100.     catch(...)
  101.     {
  102.         debug.Print("Error in GROUPAI::SplitGroup()");
  103.     }
  104.  
  105.     return newGroup;
  106. }
  107.  
  108. void GROUPAI::Goto(RECT mArea)
  109. {
  110.     if(m_members.empty())return;
  111.  
  112.     try
  113.     {
  114.         for(int i=0;i<m_members.size();i++)
  115.             if(m_members[i] != NULL && !m_members[i]->m_isBuilding && !m_members[i]->m_dead)
  116.             {
  117.                 UNIT *unit = (UNIT*)m_members[i];
  118.  
  119.                 if(unit->m_state != STATE_ATTACK)
  120.                 {
  121.                     INTPOINT p(rand()%(mArea.right - mArea.left) + mArea.left,
  122.                                 rand()%(mArea.bottom - mArea.top) + mArea.top);
  123.  
  124.                     p = unit->m_pTerrain->GetClosestFreeTile(p, unit->m_mappos);
  125.                     unit->m_pTarget = NULL;
  126.                     unit->Goto(p, false, true, STATE_MOVING);
  127.                 }
  128.             }
  129.     }
  130.     catch(...){}
  131. }
  132.  
  133. void GROUPAI::Attack(std::vector<MAPOBJECT*> &enemies)
  134. {
  135.     for(int i=0;i<m_members.size();i++)
  136.         if(!m_members[i]->m_isBuilding && !m_members[i]->m_dead)
  137.         {
  138.             UNIT *unit = (UNIT*)m_members[i];
  139.  
  140.             if(unit->m_state == STATE_IDLE || unit->m_state == STATE_MOVING)
  141.                 unit->Attack(unit->BestTargetToAttack(enemies));
  142.         }
  143. }
  144.  
  145. void GROUPAI::RetreatTo(RECT ma)
  146. {
  147.     if(m_members.empty())return;
  148.  
  149.     for(int i=0;i<m_members.size();i++)
  150.         if(!m_members[i]->m_isBuilding && !m_members[i]->m_dead)
  151.         {
  152.             UNIT *unit = (UNIT*)m_members[i];
  153.  
  154.             if(!unit->m_mappos.inRect(ma))
  155.             {
  156.                 INTPOINT p(rand()%(ma.right - ma.left) + ma.left,
  157.                             rand()%(ma.bottom - ma.top) + ma.top);
  158.  
  159.                 p = unit->m_pTerrain->GetClosestFreeTile(p, unit->m_mappos);
  160.                 unit->m_pTarget = NULL;
  161.                 unit->Goto(p, false, true, STATE_RETREAT);
  162.             }
  163.         }
  164.  
  165.     m_mapArea = ma;
  166. }
  167.  
  168. void GROUPAI::Shuffle()
  169. {
  170.     if(m_members.empty())return;
  171.  
  172.     for(int i=0;i<m_members.size();i++)
  173.         if(!m_members[i]->m_isBuilding && !m_members[i]->m_dead && rand()%40 == 0)
  174.         {
  175.             UNIT *unit = (UNIT*)m_members[i];
  176.  
  177.             INTPOINT p(rand()%(m_mapArea.right - m_mapArea.left) + m_mapArea.left,
  178.                         rand()%(m_mapArea.bottom - m_mapArea.top) + m_mapArea.top);
  179.  
  180.             p = unit->m_pTerrain->GetClosestFreeTile(p, unit->m_mappos);
  181.             unit->m_pTarget = NULL;
  182.             unit->Goto(p, false, true, STATE_MOVING);                        
  183.         }
  184. }
  185.  
  186. void GROUPAI::GroupAI()
  187. {
  188.     if(m_members.empty() || m_pMaster == NULL)return;
  189.  
  190.     int memberStates[] = {0, 0, 0};
  191.     m_state = GROUP_STATE_IDLE;
  192.  
  193.     std::vector<MAPOBJECT*>::iterator i;
  194.     for(i = m_members.begin();i != m_members.end();)
  195.     {
  196.         if((*i) == NULL || (*i)->m_dead)
  197.         {
  198.             //Remove dead Group m_members
  199.             RemoveMember(*i);
  200.         }
  201.         else 
  202.         {
  203.             (*i)->m_pGroup = this;
  204.  
  205.             //determine group m_state
  206.             if(!(*i)->m_isBuilding)
  207.             {
  208.                 UNIT *unit = (UNIT*)(*i);
  209.                 
  210.                 if(unit->m_state == STATE_ATTACK)
  211.                     memberStates[GROUP_STATE_BATTLE]++;
  212.                 else if(unit->m_moving)
  213.                     memberStates[GROUP_STATE_MOVING]++;
  214.                 else memberStates[GROUP_STATE_IDLE]++;
  215.             }
  216.             i++;
  217.         }
  218.     }
  219.  
  220.     //Set group state
  221.     if(memberStates[GROUP_STATE_BATTLE] >= m_members.size() * 0.2f)
  222.         m_state = GROUP_STATE_BATTLE;
  223.     else if(memberStates[GROUP_STATE_MOVING] >= m_members.size() * 0.4f)
  224.         m_state = GROUP_STATE_MOVING;
  225.     else m_state = GROUP_STATE_IDLE;
  226.  
  227.     //Group state machine
  228.     switch(m_state)
  229.     {
  230.         case GROUP_STATE_IDLE:
  231.         {            
  232.             if(m_task == TASK_SCOUT)
  233.             {
  234.                 AREA *area = m_pMaster->m_pStrategyMap->GetScoutArea(GetCenter());
  235.                 if(area != NULL)Goto(area->m_mapArea);
  236.             }
  237.             else if(m_task == TASK_ATTACK_LOCATION)
  238.             {
  239.                 AREA *area = m_pMaster->m_pStrategyMap->GetAttackArea(GetCenter());
  240.                 if(area != NULL)Goto(area->m_mapArea);                
  241.             }
  242.             else if(m_task == TASK_NONE || m_task == TASK_DEFEND_LOCATION)
  243.             {
  244.                 Shuffle();
  245.             }
  246.  
  247.             break;
  248.         }
  249.         case GROUP_STATE_MOVING:
  250.         {
  251.             Attack(m_visibleEnemies);
  252.  
  253.             break;
  254.         }
  255.         case GROUP_STATE_BATTLE:
  256.         {
  257.             Attack(m_visibleEnemies);
  258.  
  259.             if(m_task == TASK_DEFEND_LOCATION)
  260.                 RetreatTo(m_mapArea);
  261.  
  262.             break;
  263.         }
  264.     }
  265.  
  266.     //Report enemies to Master AI
  267.     m_pMaster->EnemiesSpotted(m_visibleEnemies);
  268.     m_visibleEnemies.clear();
  269. }
  270.  
  271. bool GROUPAI::isDead()
  272. {
  273.     return m_members.empty();
  274. }
  275.  
  276. INTPOINT GROUPAI::GetCenter()
  277. {
  278.     INTPOINT p;
  279.  
  280.     try
  281.     {
  282.         if(m_members.size() <= 0)return p;
  283.  
  284.         for(int i=0;i<m_members.size();i++)
  285.             p += m_members[i]->m_mappos;
  286.  
  287.         p /= m_members.size();
  288.     }
  289.     catch(...)
  290.     {
  291.         debug.Print("Error in GROUPAI::GetCenter()");
  292.     }
  293.  
  294.     return p;
  295. }